// Package common @author dingrui @since 2021/11/24
package common

import (
	"crypto/aes"
	"crypto/cipher"
	"crypto/md5"
	"encoding/base64"
	"encoding/binary"
	"errors"
	"fmt"
	"math/rand"
	"net"
	"net/http"
	"strconv"
	"strings"
	"time"
)

var (
	// 时区
	timeLocation, _ = time.LoadLocation("Asia/Shanghai")
	// 签名密钥
	signSecret = []byte("0123")
	// cookie密钥
	cookieSecret = []byte("hello")
)

//
//  NowUnix
//  @Description: 当前时间的时间戳
//  @return int
//
func NowUnix() int {
	return int(time.Now().In(timeLocation).Unix())
}

//
//  FormatFromUnixTime
//  @Description: 将unix时间戳格式化为yyyymmdd H:i:s格式字符串
//  @param t
//  @return string
//
func FormatFromUnixTime(t int64) string {
	if t > 0 {
		return time.Unix(t, 0).Format(TimeFormat)
	} else {
		return time.Now().Format(TimeFormat)
	}
}

//
//  FormatFromUnixTimeShort
//  @Description: 将unix时间戳格式化为yyyymmdd格式字符串
//  @param t
//  @return string
//
func FormatFromUnixTimeShort(t int64) string {
	if t > 0 {
		return time.Unix(t, 0).Format(TimeFormatShort)
	} else {
		return time.Now().Format(TimeFormatShort)
	}
}

//
//  ParseTime
//  @Description: 将字符串转成时间
//  @param str
//  @return time.Time
//  @return error
//
func ParseTime(str string) (time.Time, error) {
	return time.ParseInLocation(TimeFormat, str, timeLocation)
}

//
//  Random
//  @Description: 得到一个随机数
//  @param max
//  @return int
//
func Random(max int) int {
	var (
		r *rand.Rand
	)
	r = rand.New(rand.NewSource(time.Now().UnixNano()))
	if max < 1 {
		return r.Int()
	} else {
		return r.Intn(max)
	}
}

//
//  CreateSign
//  @Description: 对字符串进行签名
//  @param str
//  @return string
//
func CreateSign(str string) string {
	str = string(signSecret) + str
	return fmt.Sprintf("%x", md5.Sum([]byte(str)))
}

//
//  encrypt
//  @Description: 对一个字符串进行加密
//  @param key
//  @param text
//  @return []byte
//  @return error
//
func encrypt(key, text []byte) (ciphertext []byte, err error) {
	var (
		block cipher.Block
		str   string
		cfb   cipher.Stream
	)
	if block, err = aes.NewCipher(key); err != nil {
		return nil, err
	}
	str = base64.StdEncoding.EncodeToString(text)
	ciphertext = make([]byte, aes.BlockSize+len(str))
	cfb = cipher.NewCFBEncrypter(block, ciphertext[:aes.BlockSize])
	cfb.XORKeyStream(ciphertext[aes.BlockSize:], []byte(str))
	return
}

//
//  decrypt
//  @Description: 对一个字符串进行解密
//  @param key
//  @param text
//  @return []byte
//  @return error
//
func decrypt(key, text []byte) (data []byte, err error) {
	var (
		block cipher.Block
		iv    []byte
	)
	if block, err = aes.NewCipher(key); err != nil {
		return nil, err
	}
	if len(text) < aes.BlockSize {
		return nil, errors.New("ciphertext too short")
	}
	iv = text[:aes.BlockSize]
	text = text[aes.BlockSize:]
	cipher.NewCFBDecrypter(block, iv).XORKeyStream(text, text)
	return base64.StdEncoding.DecodeString(string(text))
}

//
//  Addslashes
//  @Description: 函数返回在预定义字符之前添加反斜杠的字符串 预定义字符是 单引号（'）双引号（"）反斜杠（\）
//  @param str
//  @return string
//
func Addslashes(str string) string {
	var (
		tmpRune []rune
		strRune []rune
	)
	tmpRune = []rune{}
	strRune = []rune(str)
	for _, ch := range strRune {
		switch ch {
		case []rune{'\\'}[0], []rune{'"'}[0], []rune{'\''}[0]:
			tmpRune = append(tmpRune, []rune{'\\'}[0])
			tmpRune = append(tmpRune, ch)
		default:
			tmpRune = append(tmpRune, ch)
		}
	}
	return string(tmpRune)
}

//
//  Stripslashes
//  @Description: 删除由 addslashes() 函数添加的反斜杠
//  @param str
//  @return string
//
func Stripslashes(str string) string {
	var (
		dstRune   []rune
		strRune   []rune
		strLength int
	)
	dstRune = []rune{}
	strRune = []rune(str)
	strLength = len(strRune)
	for i := 0; i < strLength; i++ {
		if strRune[i] == []rune{'\\'}[0] {
			i++
		}
		dstRune = append(dstRune, strRune[i])
	}
	return string(dstRune)
}

//
//  Ip4toInt
//  @Description: 将字符串的IP转化为数字
//  @param ip
//  @return int64
//
func Ip4toInt(ip string) int64 {
	var (
		bits []string
		sum  int64
	)
	bits = strings.Split(ip, ".")
	if len(bits) == 4 {
		b0, _ := strconv.Atoi(bits[0])
		b1, _ := strconv.Atoi(bits[0])
		b2, _ := strconv.Atoi(bits[0])
		b3, _ := strconv.Atoi(bits[0])
		sum += int64(b0) << 24
		sum += int64(b1) << 16
		sum += int64(b2) << 8
		sum += int64(b3)
		return sum
	} else {
		return 0
	}
}

//
//  NextDayDuration
//  @Description: 得到当前时间到下一天零点的延时
//  @return time.Duration
//
func NextDayDuration() time.Duration {
	var (
		year, day int
		month     time.Month
	)
	year, month, day = time.Now().Add(time.Hour * 24).Date()
	return time.Date(year, month, day, 0, 0, 0, 0, timeLocation).Sub(time.Now())
}

//
//  GetInt64
//  @Description: 从接口类型安全获取到int64
//  @param i
//  @param d
//  @return int64
//
func GetInt64(i interface{}, d int64) int64 {
	var (
		num  int
		err  error
		bits []byte
	)
	if i == nil {
		return d
	}
	switch i.(type) {
	case string:
		if num, err = strconv.Atoi(i.(string)); err != nil {
			return d
		} else {
			return int64(num)
		}
	case []byte:
		bits = i.([]byte)
		if len(bits) == 8 {
			return int64(binary.LittleEndian.Uint64(bits))
		} else if len(bits) <= 4 {
			if num, err = strconv.Atoi(string(bits)); err != nil {
				return d
			} else {
				return int64(num)
			}
		}
	case uint:
		return int64(i.(uint))
	case uint8:
		return int64(i.(uint8))
	case uint16:
		return int64(i.(uint16))
	case uint32:
		return int64(i.(uint32))
	case uint64:
		return int64(i.(uint64))
	case int:
		return int64(i.(int))
	case int8:
		return int64(i.(int8))
	case int16:
		return int64(i.(int16))
	case int32:
		return int64(i.(int32))
	case int64:
		return i.(int64)
	case float32:
		return int64(i.(float32))
	case float64:
		return int64(i.(float64))
	}
	return d
}

//
//  GetString
//  @Description: 从接口类型安全获取到字符串类型
//  @param str
//  @param d
//  @return string
//
func GetString(str interface{}, d string) string {
	if str == nil {
		return d
	}
	switch str.(type) {
	case string:
		return str.(string)
	case []byte:
		return string(str.([]byte))
	}
	return fmt.Sprintf("%s", str)
}

//
//  GetInt64FromMap
//  @Description: 从map中得到指定的key
//  @param dm
//  @param key
//  @param dft
//  @return int64
//
func GetInt64FromMap(dm map[string]interface{}, key string, dft int64) int64 {
	var (
		data interface{}
		ok   bool
	)
	if data, ok = dm[key]; !ok {
		return dft
	}
	return GetInt64(data, dft)
}

//
//  GetInt64FromStringMap
//  @Description: 从map中得到指定的key
//  @param dm
//  @param key
//  @param dft
//  @return int64
//
func GetInt64FromStringMap(dm map[string]string, key string, dft int64) int64 {
	var (
		data interface{}
		ok   bool
	)
	if data, ok = dm[key]; !ok {
		return dft
	}
	return GetInt64(data, dft)
}

//
//  GetStringFromMap
//  @Description: 从map中得到指定的key
//  @param dm
//  @param key
//  @param dft
//  @return string
//
func GetStringFromMap(dm map[string]interface{}, key string, dft string) string {
	var (
		data interface{}
		ok   bool
	)
	if data, ok = dm[key]; !ok {
		return dft
	}
	return GetString(data, dft)
}

//
//  GetStringFromStringMap
//  @Description: 从map中得到指定的key
//  @param dm
//  @param key
//  @param dft
//  @return string
//
func GetStringFromStringMap(dm map[string]string, key string, dft string) string {
	var (
		data string
		ok   bool
	)
	if data, ok = dm[key]; !ok {
		return dft
	}
	return data
}

//
//  ClientIP
//  @Description: 客户端ip地址
//  @param request
//  @return string
//
func GetClientIP(request *http.Request) (host string) {
	host, _, _ = net.SplitHostPort(request.RemoteAddr)
	return
}
